package com.xinchuang.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.poi.excel.ExcelPicUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.read.metadata.holder.ReadSheetHolder;
import com.alibaba.excel.util.ConverterUtils;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xinchuang.comment.KeyWord;
import com.xinchuang.domain.entity.DictTable;
import com.xinchuang.domain.entity.TestModelParam;
import com.xinchuang.domain.pojo.TryOutDeviceMod;
import com.xinchuang.entity.MoldSelection;
import com.xinchuang.entity.MoldSelectionDetail;
import com.xinchuang.exception.MyCustomException;
import com.xinchuang.mapper.*;
import com.xinchuang.utils.IdUtils;
import com.xinchuang.utils.ObjectUtil;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.PictureData;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @Description: 选模表读取监听器
 * @Author: thh
 * @Date: 2023/9/17 11:57
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class MoldSelectReadListener extends AnalysisEventListener<MoldSelectionDetail> {

    /**
     * db图片存储前缀
     */
    private static final String imageDbPrefix = "file/";
    /**
     * 签字前缀
     */
    private static final String makerPrefix = "承制单位签字盖章";
    /**
     * 批准前缀
     */
    private static final String approverPrefix = "批准";
    /**
     * 审核前缀
     */
    private static final String auditorPrefix = "审核";
    /**
     * 异常提示语句
     */
    private static final String exceptionPrompt = "模具编号已存在，请修改后重新导入。";
    private static final String moldIdEmpty = "承制的模具，模具编号不能为空。";
    private static final String moldNumExceptionPrompt = "模具数量请填写正整数";
    /**
     * 缓存选模数据
     */
    private List<MoldSelection> moldSelectionList = new ArrayList<>();
    /**
     * 缓存选模明细数据
     */
    private List<MoldSelectionDetail> moldSelectionDetailList = new ArrayList<>();
    /**
     * 缓存模具数据
     */
    private List<TestModelParam> testModelParamList = new ArrayList<>();
    /**
     * 缓存选模明细错误数据
     */
    private List<MoldSelectionDetail> moldSelectionDetaiErrorList = new ArrayList<>();
    /**
     * 缓存选模明细图片信息
     */
    private Map<Integer, String> moldSelectionDetailPictureMap = new HashMap<>();
    /**
     * 选模表id
     */
    private String moldSelectId = IdUtils.simpleUUID();
    /**
     * 创建人
     */
    private String createBy;
    /**
     * 文件
     */
    private MultipartFile file;
    /**
     * 因为监听器 MoldSelectReadListener 不受spring管理 所以改为构造传入
     */
    private KeyWord keyWord;
    private DictTableMapper dictTableMapper;
    private MoldSelectionMapper moldSelectionMapper;
    private TestModelParamMapper testModelParamMapper;
    private MoldSelectionDetailMapper moldSelectionDetailMapper;
    private TryOutDeviceModMapper tryOutDeviceModMapper;

    public MoldSelectReadListener(MoldSelectionMapper moldSelectionMapper, TryOutDeviceModMapper tryOutDeviceModMapper,
                                  MoldSelectionDetailMapper moldSelectionDetailMapper,
                                  String createBy, DictTableMapper dictTableMapper, MultipartFile file, KeyWord keyWord, TestModelParamMapper testModelParamMapper) {
        this.file = file;
        this.keyWord = keyWord;
        this.createBy = createBy;
        this.dictTableMapper = dictTableMapper;
        this.moldSelectionMapper = moldSelectionMapper;
        this.tryOutDeviceModMapper = tryOutDeviceModMapper;
        this.testModelParamMapper = testModelParamMapper;
        this.moldSelectionDetailMapper = moldSelectionDetailMapper;
    }

    /**
     * 这里会一行行的返回头
     *
     * @param headMap
     * @param context
     */
    @Override
    public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
        //只获取第2行的行头信息
        //{0:"项目名称：",2:"长城车体建模C673项目",4:"量产地：天津华涛",5:"天津华涛",8:"客户：",9:"长城",12:"模具数量：",14:"8套",15:"项目经理：",17:"李甲",19:"日期：",20:"2023.2.23"}
        if (context.readRowHolder().getRowIndex() == 1) {
            Map<Integer, String> map = ConverterUtils.convertToStringMap(headMap, context);
            log.info("解析到一条头数据:{}", JSON.toJSONString(map));
            //参数校验
            if (!isPositiveInteger(map.getOrDefault(14, ""))) {
                log.error("{},{}", moldNumExceptionPrompt, map.getOrDefault(14, ""));
                throw new MyCustomException(moldNumExceptionPrompt);
            }

            //选模数据
            MoldSelection moldSelection = new MoldSelection();
            moldSelection.setMoldSelectionId(moldSelectId);
            moldSelection.setProjectName(map.getOrDefault(2, ""));
            String partsFactoryName = map.getOrDefault(5, "");
            String customerName = map.getOrDefault(9, "");
            moldSelection.setPartsStorageBinName(partsFactoryName);
            moldSelection.setMainEnginePlantName(customerName);

            DictTable partsFactory = dictTableMapper.selectOne(new LambdaQueryWrapper<DictTable>()
                    .eq(DictTable::getDicName, partsFactoryName).eq(DictTable::getTypeName, "零件厂"));
            DictTable customer = dictTableMapper.selectOne(new LambdaQueryWrapper<DictTable>()
                    .eq(DictTable::getDicName, customerName).eq(DictTable::getTypeName, "主机厂"));
            if (ObjectUtil.isNotEmpty(customer)) {
                moldSelection.setMainEnginePlantId(customer.getDicId());
            }
            if (ObjectUtil.isNotEmpty(partsFactory)) {
                moldSelection.setPartsStorageBinId(partsFactory.getDicId());
            }

            moldSelection.setSetNumOfMold(map.getOrDefault(14, ""));
            moldSelection.setCustomerManager(map.getOrDefault(17, ""));
            String date = map.getOrDefault(20, "");
            if (StringUtils.isNotBlank(date)) {
                if (date.contains("-")) {
                    LocalDate parse = LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyy-M-d"));
                    moldSelection.setDate(parse);
                } else if (date.contains(".")) {
                    LocalDate parse = LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyy.M.d"));
                    moldSelection.setDate(parse);
                } else if (date.contains("/")) {
                    LocalDate parse = LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyy/M/d"));
                    moldSelection.setDate(parse);
                }
            }
            moldSelection.setStatus("0");
            moldSelection.setCreateBy(createBy);
            moldSelection.setCreateTime(LocalDateTime.now());
            moldSelectionList.add(moldSelection);
        }
    }

    /**
     * 这个每一条数据解析都会来调用
     */
    @Override
    @SneakyThrows
    public void invoke(MoldSelectionDetail moldSelectionDetail, AnalysisContext context) {
        try {
            log.info("解析到一条数据:{}", JSON.toJSONString(moldSelectionDetail));
            if (Objects.nonNull(moldSelectionDetail) && StringUtils.isNotBlank(moldSelectionDetail.getProductName())) {
                //校验数据
                TestModelParam customerMoldIdValid = isCustomerMoldIdValid(moldSelectionDetail);
                if (Objects.nonNull(customerMoldIdValid)) {
                    log.error("{}", exceptionPrompt + "模具编号: 1) " + customerMoldIdValid.getMoldId());
                    throw new MyCustomException(exceptionPrompt + "模具编号: 1) " + customerMoldIdValid.getMoldId());
                }

                //解析图片并下载
                downPictureData(context);
                //选模明细数据
                if (!moldSelectionDetailPictureMap.isEmpty()) {
                    Integer rowIndex = context.readRowHolder().getRowIndex();
                    String fileName = moldSelectionDetailPictureMap.getOrDefault(rowIndex, "");
                    if (StringUtils.isNotBlank(fileName)) {
                        moldSelectionDetail.setProductImage(imageDbPrefix + fileName);
                    }
                }
                moldSelectionDetail.setId(IdUtils.simpleUUID());
                moldSelectionDetail.setMoldSelectionId(moldSelectId);
                String machineSize = moldSelectionDetail.getMachineSize();
                try {
                    TryOutDeviceMod tryOutDeviceMod = tryOutDeviceModMapper.selectOne(new QueryWrapper<TryOutDeviceMod>().lambda().eq(TryOutDeviceMod::getDeviceName, machineSize));
                    if (ObjectUtil.isEmpty(tryOutDeviceMod)) {
                        moldSelectionDetail.setMachineSize(null);
                    } else {
                        moldSelectionDetail.setMachineSize(tryOutDeviceMod.getDeviceId());
                    }
                } catch (Exception e) {
                    log.error("机台大小：" + e);
                    moldSelectionDetail.setMachineSize(null);
                }
                moldSelectionDetailList.add(moldSelectionDetail);

                //模具数据
                String isSupply = moldSelectionDetail.getIsSupply();
                if (StringUtils.isNotBlank(isSupply) && isSupply.equals("是")) {
                    String moldId = moldSelectionDetail.getMoldId();
                    if (ObjectUtil.isEmpty(moldId)) {
                        throw new MyCustomException(moldIdEmpty + "模具名称: 1) " + moldSelectionDetail.getProductName());
                    }
                    TestModelParam testModelParam = new TestModelParam();
                    BeanUtils.copyProperties(moldSelectionDetail, testModelParam);
                    testModelParam.setCustomerMoldId(moldId);
                    testModelParam.setMaterials(moldSelectionDetail.getMaterial());
                    MoldSelection moldSelection = moldSelectionList.get(moldSelectionList.size() - 1);
                    testModelParam.setCustomerName(moldSelection.getMainEnginePlantName());
                    testModelParam.setProjectName(moldSelection.getProjectName());
                    testModelParam.setCustomerId(moldSelection.getMainEnginePlantId());
                    testModelParam.setPartsFactoryId(moldSelection.getPartsStorageBinId());
                    testModelParam.setPartsFactoryName(moldSelection.getPartsStorageBinName());
                    testModelParam.setProductName(moldSelectionDetail.getProductName());
                    testModelParam.setMoldName(moldSelectionDetail.getProductName());
                    testModelParam.setCreateTime(new Date());
                    testModelParam.setUpdateTime(new Date());
                    TestModelParam moldIdValid = isMoldIdValid(moldSelectionDetail);
                    if (Objects.nonNull(moldIdValid)) {
                        testModelParam.setMoldId(moldIdValid.getMoldId() + (System.currentTimeMillis() + ""));
                    }
                    testModelParamList.add(testModelParam);
                }
            } else {
                moldSelectionDetaiErrorList.add(moldSelectionDetail);
            }
        } catch (MyCustomException e) {
            throw new MyCustomException(e.getMessage());
        } catch (Exception e) {
            log.error("导入选模数据失败:{}", e.toString(), e);
            throw new Exception("导入选模数据失败");
        }
    }

    /**
     * 所有数据解析完成了 都会来调用
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        //重置选模表id
        moldSelectId = IdUtils.simpleUUID();
        //清空图片缓存
        moldSelectionDetailPictureMap.clear();
        //获取最后一行数据 追加 审核 批准 信息
        MoldSelectionDetail moldSelectionDetail = moldSelectionDetaiErrorList.get(moldSelectionDetaiErrorList.size() - 1);
        Map<String, Object> map = BeanUtil.beanToMap(moldSelectionDetail);
        map.forEach((k, v) -> {
            if (v instanceof String) {
                if (((String) v).startsWith(auditorPrefix)) {
                    String auditor = StringUtils.substringAfter((String) v, "：");
                    moldSelectionList.get(moldSelectionList.size() - 1).setAuditor(auditor);
                } else if (((String) v).startsWith(approverPrefix)) {
                    String approver = StringUtils.substringAfter((String) v, "：");
                    moldSelectionList.get(moldSelectionList.size() - 1).setApprover(approver);
                } else if (((String) v).startsWith(makerPrefix)) {
                    String maker = StringUtils.substringAfter((String) v, "：");
                    moldSelectionList.get(moldSelectionList.size() - 1).setMaker(maker);
                }
            }
        });
        //清空 模板明细错误数据
        moldSelectionDetaiErrorList.clear();

        log.info("所有数据解析完成！");
    }


    /**
     * 判断客户模具编号是否重复
     *
     * @return
     */
    private TestModelParam isCustomerMoldIdValid(MoldSelectionDetail moldSelectionDetail) {
        String moldId = moldSelectionDetail.getMoldId();
        if (ObjectUtil.isEmpty(moldId)) {
            return null;
        }
        List<TestModelParam> testModelParamList = testModelParamMapper.selectList(new LambdaQueryWrapper<TestModelParam>()
                .eq(TestModelParam::getCustomerMoldId, moldId));
        if (Objects.nonNull(testModelParamList) && !testModelParamList.isEmpty()) {
            return testModelParamList.get(0);
        }
        return null;
    }

    /**
     * 判断内部模具编号是否重复
     *
     * @return
     */
    private TestModelParam isMoldIdValid(MoldSelectionDetail moldSelectionDetail) {
        List<TestModelParam> testModelParamList = testModelParamMapper.selectList(new LambdaQueryWrapper<TestModelParam>()
                .eq(TestModelParam::getMoldId, moldSelectionDetail.getMoldId()).orderByDesc(TestModelParam::getCreateTime));
        if (Objects.nonNull(testModelParamList) && !testModelParamList.isEmpty()) {
            return testModelParamList.get(0);
        }
        return null;
    }

    /**
     * 保存选模数据
     */
    public void saveMoldSelection() {
        if (!moldSelectionList.isEmpty()) {
            int i = moldSelectionMapper.insertMoldSelectionBatch(moldSelectionList);
            log.info("选模数据入库成功,size:{}", i);
            // 存储完成清理 list
            moldSelectionList.clear();
        }
    }

    /**
     * 保存选模明细数据
     */
    public void saveMoldSelectionDetail() {
        if (!moldSelectionDetailList.isEmpty()) {
            int i = moldSelectionDetailMapper.insertMoldSelectionDetailBatch(moldSelectionDetailList);
            log.info("选模明细数据入库成功,size:{}", i);
            // 存储完成清理 list
            moldSelectionDetailList.clear();
        }
    }

    /**
     * 保存模具数据
     */
    public void saveTestModelParam() {
        if (!testModelParamList.isEmpty()) {
            int i = testModelParamMapper.insertTestModelParamBatch(testModelParamList);
            log.info("模具数据入库成功,size:{}", i);
            // 存储完成清理 list
            testModelParamList.clear();
        }
    }

    /**
     * 下载图片信息
     *
     * @param analysisContext
     * @return
     */
    private void downPictureData(AnalysisContext analysisContext) throws Exception {
        try {
            //存储图片
            if (moldSelectionDetailPictureMap.isEmpty()) {
                ReadSheetHolder sheetHolder = analysisContext.readSheetHolder();
                if (sheetHolder != null) {
                    // 获取当前 sheet 页的索引
                    int currentSheetIndex = sheetHolder.getSheetNo();
                    //获取图片信息
                    ExcelReader reader = ExcelUtil.getReader(file.getInputStream());
                    Map<String, PictureData> picMap = ExcelPicUtil.getPicMap(reader.getWorkbook(), currentSheetIndex);
                    picMap.forEach((k, v) -> {
                        if (StringUtils.substringAfter(k, "_").equals("3")) {
                            String fileName = System.currentTimeMillis() + "_" + RandomUtil.randomString(5) + StrPool.DOT + v.suggestFileExtension();
                            FileUtil.writeBytes(v.getData(), keyWord.getFileUrl() + File.separator + "file" + File.separator + fileName);
                            //因为表头的缘故 excel 从第5行开始读取的 所以要减去 数值 3(索引从0开始)
                            moldSelectionDetailPictureMap.put(Integer.valueOf(StringUtils.substringBefore(k, "_")), fileName);
                        }
                    });
                }
            }
        } catch (Exception e) {
            log.error("导入选模数据时存储图片失败:{}", e.toString(), e);
            throw new Exception("导入选模数据时存储图片失败");
        }
    }

    /**
     * 校验excel本身是否存在重复的客户模具编号
     */
    public void validHasDuplicateMoldId() {
        List<String> list = moldSelectionDetailList.stream()
                .filter(m -> ObjectUtil.isNotEmpty(m.getMoldId()))
                .collect(Collectors.groupingBy(MoldSelectionDetail::getMoldId))
                .entrySet()
                .stream()
                .filter(entry -> entry.getValue().size() > 1)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());

        if (Objects.nonNull(list) && !list.isEmpty()) {
            StringBuffer sb = new StringBuffer("模具编号: ");
            sb.append(IntStream.range(0, list.size())
                    .mapToObj(i -> (i + 1) + ") " + list.get(i))
                    .collect(Collectors.joining(" ")));
            log.error("{}", exceptionPrompt + sb.toString());
            throw new MyCustomException(exceptionPrompt + sb.toString());
        }
    }

    /**
     * 校验是否是正整数
     *
     * @param parameter
     * @return
     */
    public static boolean isPositiveInteger(String parameter) {
        return parameter.matches("\\d+") && !parameter.startsWith("0");
    }

}
